package org.example.ThreadPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/*
    int corePoolSize:线程池当中所一直维护的线程数量，如果线程池处于任务空闲期间，那么该线程也并不会被回收掉
    int maximumPoolSize:线程池中所维护的线程数的最大数量
    long keepAliveTime:超过了corePoolSize的线程在经过keepAliveTime时间后如果一直处于空闲状态，那么超过的这部分线程将会被回收掉
    TimeUnit unit:指的是keepAliveTime的时间单位
    BlockingQueue<Runnable>workQueue:向线程池所提交的任务位于的阻塞队列，它的实现有多种方式
    ThreadFactory threadFactory:线程工厂，用于创建新的线程并被线程池所管理，默认线程工厂所创建的线程都是用户线程且优先级为正常优先级
    RejectedExecutionHandler handler:表示当线程池中的线程都在忙于执行任务且阻塞队列也已经满了的情况下，新到来的任务该如何被对待和处理。
        它有四种实现策略：
            AbortPolicy:直接抛出一个运行期异常。
            DiscardPolicy:默默地丢弃掉提交的任务，什么都不做且不抛出任何异常
            DiscardoldestPolicy:丢弃掉阻塞队列中存放时间最久的任务(队头元素),并且为当前所提交的任务留出一个队列中的空闲空间，以便将其放进到队列中
            CallerRunsPolicy:直接由提交任务的线程来运行这个提交的任务
* */
/*
    对于线程池来说，其提供了execute与submit两种方式来向线程池提交任务
    总体来说，submit方法是可以取代execute方法的，因为它既可以接收Callable任务，也可以接收Runnable任务。
    但是，submit方法相比于execute方法来说，它能够返回一个Future对象，通过这个Future对象可以得知任务是否执行成功。
    但是，如果仅仅是为了执行Runnable任务的话，那么使用execute方法会更加简单。

    关于线程池的总体执行策略：
        1.如果线程池中正在执行的线程数<corePoolSize,那么线程池就会优先选择创建新的线程而非将提交的任务加到阻塞队列中。
        2.如果线程池中正在执行的线程数>=corePoolSize,那么线程池就会优先选择对提交的任务进行阻塞排队而非创建新的线程。
        3.如果提交的任务无法加入到阻塞队列当中，那么线程池就会创建新的线程；如果创建的线程数超过了maximumPoolSize,那么拒绝策略就会起作用。

    关于线程池任务提交的总结：
        1.两种提交方式：submit与execute
        2.submit有三种方式，无论哪种方式，最终都是将传递进来的任务转换为一个callable对象进行处理
        3.当Callable对象构造完毕后，最终都会调用Executor接口中声明的execute方法进行统一的处理

    对于线程池来说，存在两个状态需要维护：
        1.线程池本身的状态：ctl的高3位来表示
        2.线程池中所运行着的线程的数量：ctl的其余29位来表示
    线程池一共存在5种状态：
        1.RUNNING:线程池可以接收新的任务提交，并且还可以正常处理阻塞队列中的任务。
        2.SHUTDOWN:不再接收新的任务提交，不过线程池可以继续处理阻塞队列中的任务。
        3.STOP:不再接收新的任务，同时还会丢弃阻塞队列中的既有任务；此外，它还会中断正在处理中的任务。
        4.TIDYING:所有的任务都执行完毕后(同时也涵盖了阻塞队列中的任务),当前线程池中的活动的线程数量降为0,将会调用terminated方法。
        5.TERMINATED:线程池的终止状态，当terminated方法执行完毕后，线程池将会处于该状态之下。

    线程状态变迁：
        RUNNING->SHUTDOWN:当调用了线程池的shutdown方法时，或者当finalize方法被隐式调用后(该方法内部会调用shutdown方法)
        RUNNING,SHUTDOWN ->STOP:当调用了线程池的shutdownNow方法时
        SHUTDOWN ->TIDYING:在线程池与阻塞队列均变为空时
        STOP->TIDYING:在线程池变为空时
        TIDYING ->TERMINATED:在terminated方法被执行完毕时
* */

public class ThreadPoolExecutorSty {
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue(3), new ThreadPoolExecutor.AbortPolicy());
        IntStream.range(0, 9).forEach(i -> {
            executorService.submit(() -> {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                IntStream.range(0, 10).forEach(j -> {
                    System.out.println(Thread.currentThread().getName());
                });
            });
        });

        executorService.shutdown();
    }

}
